package com.iot08.api.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.green20220302.Client;
import com.aliyun.green20220302.models.*;
import com.aliyun.green20220302.models.ImageModerationResponseBody.ImageModerationResponseBodyData;
import com.aliyun.green20220302.models.ImageModerationResponseBody.ImageModerationResponseBodyDataResult;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.iot08.api.config.redis.RedisVideoService;
import com.iot08.api.service.MessageStatsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.*;

/**
 * @author weichao 1299101858@qq.com
 * @version 1.0
 * @date 7/6/23 10:14 AM
 */
@Slf4j
@Component
public class ContentSecurityUtil {
    private static Client staticClient;
    /**
     * taskId 任务ID 和 openIdOrDevId groupId msgId 的对应关系存储在Account Redis中, 用于回调处理.
     */
    public static String ChatAudioKey = "ChatA_CSKey:";

    /*
    静态例子
    public static String DOMAIN;

    @Value("${aliyun.oss.domain}")
    public void setDomain(String domain){
        DOMAIN = domain;
    }
    */
    // 对应企业邮箱的密码

    private static String accessKeyId;

    @Value("${contentSecurity.accessKeyId:}")
    public void setAccessKeyId(String aAccessKeyId) {
        accessKeyId = aAccessKeyId;
    }


    private static String accessKeySecret;

    @Value("${contentSecurity.accessKeySecret:}")
    public void setAccessKeySecret(String aAccessKeySecret) {
        accessKeySecret = aAccessKeySecret;
    }

    private static String chatAudoiCallback;

    @Value("${contentSecurity.chatAudoiCallback:}")
    public void setChatAudoiCallback(String aChatAudoiCallback) {
        chatAudoiCallback = aChatAudoiCallback;
    }

    private static Integer chatSwitch;

    @Value("${contentSecurity.chatSwitch:0}")
    public void setChatSwitch(Integer aChatSwitch) {
        chatSwitch = aChatSwitch;
    }

    private static Integer nicknameAndDeviceImgSwitch;

    @Value("${contentSecurity.nicknameAndDeviceImgSwitch:0}")
    public void setNicknameAndDeviceImgSwitch(Integer aNicknameAndDeviceImgSwitch) {
        nicknameAndDeviceImgSwitch = aNicknameAndDeviceImgSwitch;
    }

    @Resource
    private RedisVideoService redisVideoService;

    // 静态变量保存依赖
    private static MessageStatsService staticMessageStatsService;

    // 实例成员（用于注入）
    @Resource
    private MessageStatsService messageStatsService;

    // 初始化静态变量
    @PostConstruct
    public void init() {
        staticMessageStatsService = this.messageStatsService;
    }


    /**
     * 获取配置 最好是默认内网
     *
     * @param type
     * @return
     */
    private static Config getConfig(int type) {
        Config config = new Config();
        config.setAccessKeyId(accessKeyId);
        config.setAccessKeySecret(accessKeySecret);
        //接入区域和地址请根据实际情况修改
        if (type == 0) {
            config.setRegionId("cn-shanghai");
            //公网
            config.setEndpoint("green-cip.cn-shanghai.aliyuncs.com");
            //内网
            //config.setEndpoint("green-cip-vpc.cn-shanghai.aliyuncs.com");
        } else {
            config.setRegionId("cn-beijing");
            //公网
            config.setEndpoint("green-cip.cn-beijing.aliyuncs.com");
            //内网
            //config.setEndpoint("green-cip-vpc.cn-beijing.aliyuncs.com");
        }

        //连接时超时时间，单位毫秒（ms）。
        config.setReadTimeout(6000);
        //读取时超时时间，单位毫秒（ms）。
        config.setConnectTimeout(3000);
        //设置http代理。
        //config.setHttpProxy("http://10.10.xx.xx:xxxx");
        //设置https代理。
        //config.setHttpsProxy("https://10.10.xx.xx:xxxx");
        // 注意，此处实例化的client请尽可能重复使用，避免重复建立连接，提升检测性能
        return config;
    }

    private static Client getClient() {
        if (staticClient == null) {
            try {

                staticClient = new Client(getConfig(0));
            } catch (Exception e) {
                log.error("初始化阿里云内容安全 实例对象出错 e:" + e.getMessage(), e);
                return null;
            }
        }
        return staticClient;

    }

    /**
     * 设备昵称 内容安全 审查
     *
     * @param content
     * @return
     */
    public static boolean nicknameAudit(String content) {
        if (nicknameAndDeviceImgSwitch == 0) {
            //开关没打开 ,直接返回不敏感结果
            return true;
        }
        return textAudit(content, 0);
    }


    /**
     * 文本内容 内容安全 审查
     *
     * @param content
     * @return
     */

    private static boolean textAudit(String content, int type) {
        if (StringUtils.isEmpty(content)) {
            //空直接返回成功
            return true;
        }
        // 创建RuntimeObject实例并设置运行参数。
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = 10000;
        runtime.connectTimeout = 10000;

        //检测参数构造
        JSONObject serviceParameters = new JSONObject();
        serviceParameters.put("content", content);

        TextModerationRequest textModerationRequest = new TextModerationRequest();
        /*
        文本检测服务 service code
        审核服务类型，包括： 7.5元/万次

            nickname_detection：用户昵称

            chat_detection：私聊互动

            comment_detection：公聊评论

            ai_art_detection：AIGC文字指令

            ad_compliance_detection：广告法合规

            pgc_detection：教学物料PGC
        */
        if (type == 0) {
            textModerationRequest.setService("nickname_detection"); //默认 用户昵称
        } else if (type == 1) {
            textModerationRequest.setService("chat_detection");
        }

        textModerationRequest.setServiceParameters(serviceParameters.toJSONString());
        try {
            // 调用方法获取检测结果。
            TextModerationResponse response = getClient().textModerationWithOptions(textModerationRequest, runtime);

            // 自动路由。
            if (response != null) {
                // 服务端错误，区域切换到cn-beijing。
                if (500 == response.getStatusCode() || (response.getBody() != null && 500 == (response.getBody().getCode()))) {
                    // 接入区域和地址请根据实际情况修改。
                    Config config = getConfig(1);
                    staticClient = new Client(config);
                    response = staticClient.textModerationWithOptions(textModerationRequest, runtime);
                }
            }
            // 打印检测结果。
            if (response != null) {
                if (response.getStatusCode() == 200) {
                    TextModerationResponseBody result = response.getBody();
                    Integer code = result.getCode();
                    if (code != null && code == 200) {
                        TextModerationResponseBody.TextModerationResponseBodyData data = result.getData();
                        // labels 是 "" 表示正常, 有标签则表示不正常
                        if (data.getLabels().isEmpty()) {
                            //表示正常
                            return true;
                        } else {
                            //检测到敏感词
                            log.info("内容安全 文字审核 检测到敏感词, 输入的内容:{} 接口返回的内容:{}", content, response.toMap());
                            return false;
                        }

                    } else {
                        log.error("输入的内容:{} 内容安全 文字审核 text moderation not success. code:" + code, content);
                    }
                } else {
                    log.error("输入的内容:{} 内容安全 文字审核 response not success. status:" + response.getStatusCode(), content);
                }
            }
        } catch (Exception e) {
            log.error("输入的内容:" + content + " 内容安全 文字审核 代码异常:" + e.getMessage(), e);
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 头像图片 内容安全 审查
     *
     * @param imgUrl
     * @return
     */
    public static boolean imageAudit(String imgUrl,String openIdOrDevId) {
        if (StringUtils.isEmpty(imgUrl)) {
            //空直接返回成功
            return true;
        }

        // 检测前记录成功统计
        if (staticMessageStatsService != null && StringUtils.isNotEmpty(openIdOrDevId)) {
            staticMessageStatsService.updateSuccess(openIdOrDevId);
        }

        if (nicknameAndDeviceImgSwitch == 0) {
            //开关没打开 ,直接返回不敏感结果
            return true;
        }
        // 创建RuntimeObject实例并设置运行参数。
        RuntimeOptions runtime = new RuntimeOptions();
        runtime.readTimeout = 10000;
        runtime.connectTimeout = 10000;

        //检测参数构造
        Map<String, String> serviceParameters = new HashMap<>();
        //公网可访问的URL。
        serviceParameters.put("imageUrl", imgUrl);
        serviceParameters.put("dataId", UUID.randomUUID().toString());

        ImageModerationRequest request = new ImageModerationRequest();
        //图片检测service: baselineCheck 通用基线检测。
        /*
        图片检测增强版支持的检测服务,取值：
            //图片审核通用版（image_standard） 15元/万次
            baselineCheck：通用基线检测
            baselineCheck_pro：通用基线检测_专业版
            baselineCheck_cb：通用基线检测_海外版
            //图片审核高级版（image_advanced） 30元/万次
            tonalityImprove：内容治理检测
            aigcCheck：AIGC图片检测
            profilePhotoCheck：头像图片检测
        */
        request.setService("profilePhotoCheck");
        request.setServiceParameters(JSON.toJSONString(serviceParameters));

        try {
            // 调用方法获取检测结果。
            ImageModerationResponse response = getClient().imageModerationWithOptions(request, runtime);

            // 自动路由。
            if (response != null) {
                // 服务端错误，区域切换到cn-beijing。
                if (500 == response.getStatusCode() || (response.getBody() != null && 500 == (response.getBody().getCode()))) {
                    // 接入区域和地址请根据实际情况修改。
                    Config config = getConfig(1);
                    staticClient = new Client(config);
                    response = staticClient.imageModerationWithOptions(request, runtime);
                }
            }
            //打印检测结果
            /*
            当系统没有检测到风险内容时，返回示例：
            {
                "Msg": "OK",
                "Code": 200,
                "Data": {
                    "dataId": "uimg123****",
                    "result": [
                        {
                            "label": "nonLabel"
                        }
                    ]
                },
                "RequestId": "ABCD1234-1234-1234-1234-1234XYZ"
            }
            有风险时
            {
              "Msg": "success",
              "RequestId": "65786533-860E-5C6B-BFCB-41827E6D33ED",
              "Data": {
                "DataId": "img1234567",
                "Result": [
                  {
                    "Confidence": 98.47,
                    "Label": "political_politicalFigure"
                  },
                  {
                    "Confidence": 94.89,
                    "Label": "political_historicalNihility"
                  }
                ]
              },
              "Code": 200
            }
            */
            if (response != null) {
                if (response.getStatusCode() == 200) {
                    ImageModerationResponseBody body = response.getBody();
//                    System.out.println("requestId=" + body.getRequestId());
//                    System.out.println("code=" + body.getCode());
//                    System.out.println("msg=" + body.getMsg());
                    if (body.getCode() == 200) {
                        ImageModerationResponseBodyData data = body.getData();
//                        System.out.println("dataId=" + data.getDataId());
                        List<ImageModerationResponseBodyDataResult> results = data.getResult();
                        if (results.size() == 1) {
                            ImageModerationResponseBodyDataResult result = results.get(0);
                            if (result.getLabel().equalsIgnoreCase("nonLabel")) {
                                //表示正常
                                return true;
                            } else {
                                log.info("内容安全 图片审核 检测到敏感图片, 输入的内容:{} 接口返回的内容:{}", imgUrl, response.toMap());
                                // 审核失败，记录错误统计
                                if (staticMessageStatsService != null && StringUtils.isNotEmpty(openIdOrDevId)) {
                                    staticMessageStatsService.updateError(openIdOrDevId);
                                }
                                return false;
                            }
                        } else {
                            log.info("内容安全 图片审核 检测到敏感图片, 输入的内容:{} 接口返回的内容:{}", imgUrl, response.toMap());
                            // 审核失败，记录错误统计
                            if (staticMessageStatsService != null && StringUtils.isNotEmpty(openIdOrDevId)) {
                                staticMessageStatsService.updateError(openIdOrDevId);
                            }
                            return false;
                        }
                    } else {
                        log.error("输入的内容:{} 内容安全 图片审核 image moderation not success. code:" + body.getCode(), imgUrl);
                    }
                } else {
                    log.error("输入的内容:{} 内容安全 图片审核 response not success. status:" + response.getStatusCode(), imgUrl);
                }
            }
        } catch (Exception e) {
            log.error("输入的内容:" + imgUrl + " 内容安全 图片审核 代码异常:" + e.getMessage(), e);
        }
        return false;
    }


    /**
     * 微聊内容 内容安全 审查
     *
     * @param content
     * @return false: 审查不通过
     */

    public boolean chatTextAudit(String content, String userId) {
        // 检测前记录成功统计
        if (staticMessageStatsService != null && StringUtils.isNotEmpty(userId)) {
            staticMessageStatsService.updateSuccess(userId);
        }

        if (chatSwitch == 0) {
            //开关没打开 ,直接返回不敏感结果
            return true;
        }

        // 根据失败率决定是否调用审核API
        if (!shouldCallAuditApi(userId)) {
            return true; // 跳过审核，默认通过
        }
        int count = checkPhraseAudit(content);
        if (count > 1) {
            //命中词组 2次以上, 审查不通过
            // 审核失败，记录错误统计
            if (staticMessageStatsService != null && StringUtils.isNotEmpty(userId)) {
                staticMessageStatsService.updateError(userId);
            }
            return false;
        }
        boolean result = textAudit(content, 1);
        if (!result) {
            // 审核失败，记录错误统计
            if (staticMessageStatsService != null && StringUtils.isNotEmpty(userId)) {
                staticMessageStatsService.updateError(userId);
            }
        }
        return result;
    }

    /**
     * 微聊语音 内容安全 审查
     *
     * @param amrUrl
     * @return
     */
    public boolean chatAudioAudit(String amrUrl, String openIdOrDevId, String groupId, String msgId) {
        // 检测前记录成功统计
        if (staticMessageStatsService != null && StringUtils.isNotEmpty(openIdOrDevId)) {
            staticMessageStatsService.updateSuccess(openIdOrDevId);
        }
        if (chatSwitch == 0) {
            //开关没打开 ,直接返回不敏感结果 / 不检查
            return true;
        }

        // 根据失败率决定是否调用审核API
        if (!shouldCallAuditApi(openIdOrDevId)) {
            return true; // 跳过审核，默认通过
        }

        JSONObject serviceParameters = new JSONObject();
        serviceParameters.put("url", amrUrl);
        serviceParameters.put("callback", chatAudoiCallback);
        serviceParameters.put("seed", "jianyou");
        VoiceModerationRequest voiceModerationRequest = new VoiceModerationRequest();
        // 检测类型：audio_media_detection表示语音文件检测，live_stream_detection表示语音直播流检测。
        voiceModerationRequest.setService("audio_media_detection");
        voiceModerationRequest.setServiceParameters(serviceParameters.toJSONString());
        try {
            VoiceModerationResponse response = getClient().voiceModeration(voiceModerationRequest);
            if (response.getStatusCode() == 200) {
                VoiceModerationResponseBody result = response.getBody();
                Integer code = result.getCode();
                if (200 == code) {
                    log.info("微聊语音 内容安全 审查提交成功: result:{} openIdOrDevId:{} groupId:{} msgId:{}", JSONObject.toJSONString(result), openIdOrDevId, groupId, msgId);

                    //请求成功,记录  taskId 任务ID 和 openIdOrDevId groupId msgId url 的对应关系存储在Video的 Redis中, 用于回调处理.
                    VoiceModerationResponseBody.VoiceModerationResponseBodyData data = result.getData();
                    String taskId = data.getTaskId();
                    //存一个小时 24*60*60 = 24*3600
                    redisVideoService.setex(ChatAudioKey + taskId, 24 * 3600, String.format("%s&%s&%s&%s", openIdOrDevId, groupId, msgId, amrUrl));
                    return true;
                } else {
                    log.error("voice moderation not success. openIdOrDevId:{} groupId:{} msgId:{} result:{}", openIdOrDevId, groupId, msgId, JSONObject.toJSONString(result));
                    return false;
                }
            } else {
                log.error("response not success. openIdOrDevId:{} groupId:{} msgId:{} status:{}", openIdOrDevId, groupId, msgId, response.getStatusCode());
                return false;
            }
        } catch (Exception e) {
            log.error("微聊语音 内容安全 审查提交错误: error:" + e.getMessage(), e);
            return false;
        }
    }

    /**
     * 根据失败率计算是否需要调用审核API
     * @param userId 用户ID
     * @return true-需要调用审核，false-跳过审核
     */
    private static boolean shouldCallAuditApi(String userId) {
        if (StringUtils.isEmpty(userId) || staticMessageStatsService == null) {
            // 没有用户ID或服务未初始化，默认调用审核
            return true;
        }

        // 获取失败百分比
        String errorPercentageStr = staticMessageStatsService.getErrorPercentage(userId);
        int errorPercentage = Integer.parseInt(errorPercentageStr.replace("%", ""));

        // 根据失败率计算调用概率
        // 失败率越高，调用概率越高
        // 0% 失败率 -> 40% 调用概率（最低抽检率）
        // 10% 失败率 -> 40% 调用概率
        // 20% 失败率 -> 60% 调用概率
        // 30% 失败率 -> 80% 调用概率
        // 40%+ 失败率 -> 100% 调用概率（全部审核）

        int callProbability;
        if (errorPercentage == 0) {
            callProbability = 40; // 最低保持40%的抽检
        } else if (errorPercentage <= 10) {
            callProbability = 20 + errorPercentage * 2;
        } else if (errorPercentage <= 20) {
            callProbability = 40 + (errorPercentage - 10) * 2;
        } else if (errorPercentage <= 30) {
            callProbability = 60 + (errorPercentage - 20) * 2;
        } else if (errorPercentage <= 40) {
            callProbability = 80 + (errorPercentage - 30) * 2;
        } else {
            callProbability = 100; // 失败率超过40%，全部审核
        }

        // 生成随机数决定是否调用
        Random random = new Random();
        int randomValue = random.nextInt(100);

        boolean shouldCall = randomValue < callProbability;

        if (!shouldCall) {
            log.info("跳过内容审核 - 用户: {}, 失败率: {}%, 调用概率: {}%, 随机数: {}",
                    userId, errorPercentage, callProbability, randomValue);
        }

        return shouldCall;
    }

    /**
     * 检测词组
     *
     * @param content
     * @return 命中词组 次数
     */
    private static int checkPhraseAudit(String content) {
        /**
         * #涉爆炸物品的关键词组
         * 【原材料】硫磺、碳粉、硝酸钾、导火线、木炭粉、火药、引线、电雷管等
         * 【制作工具】电子秤、研磨器具、玻璃烧杯、电子点火头等
         * 【搜索动作】火药制作、火药比例等
         * #涉枪的关键词组
         * 【性能】火狗、气狗、火粮、狗粮、铅蛋等
         * 【型号】CZ527、AR15、板球、夜莺、野猫、山猫、柯尔特ED、罗拉、火神、虎贲等
         * 【配件】改件、母鸡、航母、秃子、模具、夹、瞄具、恒压阀、弹轮、座子等
         * 【口径】英寸的.45与.50，毫米的11.43、12.7、9、7.62等
         * 【来源】进口、原装、广华街、唐番九、三军、枪天堂、菲律宾、意大利、台湾、美国、泰国等
         */
        JSONArray phraseList = new JSONArray();
        String[] word1 = {"硫磺", "碳粉", "硝酸钾", "导火线", "木炭粉", "火药", "引线", "电雷管"};
        String[] word2 = {"电子秤", "研磨器具", "玻璃烧杯", "电子点火头"};
        String[] word3 = {"火药制作", "火药比例"};
        String[] word4 = {"火狗", "气狗", "火粮", "狗粮", "铅蛋"};
        String[] word5 = {"CZ527", "AR15", "板球", "夜莺", "野猫", "山猫", "柯尔特ED", "罗拉", "火神", "虎贲"};
        String[] word6 = {"改件", "母鸡", "航母", "秃子", "模具", "夹", "瞄具", "恒压阀", "弹轮", "座子"};
        String[] word7 = {"英寸的.45与.50", "毫米的11.43", "12.7", "9", "7.62"};
        String[] word8 = {"进口", "原装", "广华街", "唐番九", "三军", "枪天堂", "菲律宾", "意大利", "台湾", "美国", "泰国"};
        phraseList.add(word1);
        phraseList.add(word2);
        phraseList.add(word3);
        phraseList.add(word4);
        phraseList.add(word5);
        phraseList.add(word6);
        phraseList.add(word7);
        phraseList.add(word8);


        int count = 0;
        for (int i = 0; i < phraseList.size(); i++) {
            String[] item = phraseList.getObject(i, String[].class);
            for (int j = 0; j < item.length; j++) {
                if (content.contains(item[j])) {
                    count += 1;
                }
            }
        }
//        if (count>1){
//            //返回敏感结果: 命中
//            return true;
//        }
//        return false;
        return count;
    }


    public static void main(String[] args) throws Exception {
//        boolean textRes = textAudit("xijinping");
//        boolean imgRes = imageAudit("https://bkimg.cdn.bcebos.com/pic/5882b2b7d0a20cf431ad7f26d25f5c36acaf2fdd3389?x-bce-process=image/resize,m_lfit,w_536,limit_1/format,f_auto");
//        log.info("textRes {}, imgRes {}", textRes , imgRes);
//        String content = "意大利来的电子点火头";
        String content = "需要的制造工具:电子秤,火药,铅蛋";
        System.out.println("检查词组:" + content + " 结果:" + checkPhraseAudit(content));

    }
}
